﻿using crypto_all.SM;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Text;
using BigInteger = Org.BouncyCastle.Math.BigInteger;

namespace crypto_all.KMS
{
    public class SM2Provider : ISM
    {
        private string CMK_Private;
        private string CMK_Public;
        public SM2Provider()
        {
            var tuple = GetSM2Keys(false);
            CMK_Public = tuple.PublicKey;
            CMK_Private = tuple.PrivateKey;
        }
        public string GetDataKey(string encryptedDataKey)
        {
            return Encoding.Default.GetString(SM2Utils.Decrypt(HexStringToByteArray(CMK_Private), HexStringToByteArray(encryptedDataKey)));
        }

        public (string DataKey, string EncryptedDataKey) GetDataKeyTuple()
        {
            var tuple = GetSM2Keys();
            var dataKey = tuple.PublicKey;
            var encryptedDataKey = SM2Utils.Encrypt(HexStringToByteArray(CMK_Public), Encoding.Default.GetBytes(tuple.PrivateKey));
            return (dataKey, encryptedDataKey);
        }

        private (string PublicKey, string PrivateKey) GetSM2Keys(bool randomGen = true) 
        {

            if (randomGen)
            {
                AsymmetricCipherKeyPair key = SM2Utils.GenerateKeyPair();
                ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)key.Private;
                ECPublicKeyParameters ecpub = (ECPublicKeyParameters)key.Public;
                BigInteger privateKey = ecpriv.D;
                ECPoint publicKey = ecpub.Q;
                string pubKey = Encoding.ASCII.GetString(Hex.Encode(publicKey.GetEncoded())).ToUpper();
                string privKey = Encoding.ASCII.GetString(Hex.Encode(privateKey.ToByteArray())).ToUpper();
                return (pubKey, privKey);
            }
            else 
            {
                string pubKey = "0447806CC1B1BEA42AB47A73A52A0B37FA6D8ABF4EB3C86789057F326CE1CE27C42A76766187DE225BB2C28E6741A7921BF122F19F77762625A53248F55CF40993";
                string privKey = "3D435FC28D6A2432BC2294C3671508DE6AE4E0A7968156531CCE4EAE7E61B29E";
                return (pubKey, privKey);
            }
        }
        public byte[] HexStringToByteArray(string s)
        {
            s = s.Replace(" ", "");
            byte[] buffer = new byte[s.Length / 2];
            for (int i = 0; i < s.Length; i += 2)
            {
                buffer[i / 2] = Convert.ToByte(s.Substring(i, 2), 16);
            }

            return buffer;
        }
    }
}
